; UNSUPPORTED: system-windows
;   See https://github.com/llvm/circt/issues/4128
; RUN: rm -rf %t
; RUN: firtool --repl-seq-mem --repl-seq-mem-file=mems.conf --split-verilog --emit-omir -o=%t %s
; RUN: FileCheck %s --check-prefix=TESTHARNESS < %t/TestHarness.sv
; RUN: FileCheck %s --check-prefix=DUTMODULE < %t/Prefix_DUTModule.sv
; RUN: FileCheck %s --check-prefix=SEQMEMSGROUP < %t/Prefix_SeqMemsGroup.sv
; RUN: FileCheck %s --check-prefix=INJECTEDSUBMODULE < %t/Prefix_InjectedSubmodule.sv
; RUN: FileCheck %s --check-prefix=SOMEMODULE < %t/Prefix_SomeModule.sv
; RUN: FileCheck %s --check-prefix=MEM < %t/Prefix_mem.sv
; RUN: FileCheck %s --check-prefix=MEMS-CONF < %t/mems.conf
; RUN: FileCheck %s --check-prefix=SEQMEMS-TXT < %t/SeqMems.txt
; RUN: FileCheck %s --check-prefix=OMIR < %t/omir.json

; Extracted from test/scala/firrtl/ExtractSeqMems.scala
; Checks that instance extraction composes with:
; - Dedup
; - OMIR emission and SRAM path setting
; - Inject DUT Hierarchy
; - Prefixing

FIRRTL version 4.0.0
circuit TestHarness : %[[
  {
    "class":"sifive.enterprise.firrtl.NestedPrefixModulesAnnotation",
    "target":"~TestHarness|DUTModule",
    "prefix":"Prefix_",
    "inclusive":true
  },
  {
    "class":"sifive.enterprise.firrtl.InjectDUTHierarchyAnnotation",
    "name":"InjectedSubmodule"
  },
  {
    "class":"sifive.enterprise.firrtl.ExtractSeqMemsFileAnnotation",
    "filename":"SeqMems.txt",
    "group":"SeqMemsGroup"
  },
  {
    "class":"sifive.enterprise.firrtl.MarkDUTAnnotation",
    "target":"TestHarness.DUTModule"
  },
  {
    "class": "freechips.rocketchip.objectmodel.OMIRFileAnnotation",
    "filename": "omir.json"
  },
  {
    "class": "freechips.rocketchip.objectmodel.OMIRAnnotation",
    "nodes": [
      {
        "info": "",
        "id": "OMID:0",
        "fields": [
          {"info": "", "name": "omType", "value": ["OMString:OMLazyModule", "OMString:OMSRAM"]},
          {"info": "", "name": "finalPath", "value": "OMMemberInstanceTarget:~TestHarness|SomeModule>mem"}
        ]
      },
      {
        "info": "",
        "id": "OMID:1",
        "fields": [
          {"info": "", "name": "omType", "value": ["OMString:OMLazyModule", "OMString:OMSRAM"]},
          {"info": "", "name": "finalPath", "value": "OMMemberReferenceTarget:~TestHarness|SomeModule_1>mem"}
        ]
      }
    ]
  }
]]
  module SomeModule :
    input clock : Clock
    input reset : Reset
    output io : { flip addr : UInt<3>, flip dataIn : UInt<8>, flip wen : UInt<1>, dataOut : UInt<8>}

    smem mem : UInt<8> [8]
    infer mport read = mem[io.addr], clock
    connect io.dataOut, read
    when io.wen :
      infer mport write = mem[io.addr], clock
      connect write, io.dataIn

  module SomeModule_1 :
    input clock : Clock
    input reset : Reset
    output io : { flip addr : UInt<3>, flip dataIn : UInt<8>, flip wen : UInt<1>, dataOut : UInt<8>}

    smem mem : UInt<8> [8]
    infer mport read = mem[io.addr], clock
    connect io.dataOut, read
    when io.wen :
      infer mport write = mem[io.addr], clock
      connect write, io.dataIn

  ; DUTMODULE: module Prefix_DUTModule
  ; DUTMODULE: SeqMemsGroup SeqMemsGroup
  ; DUTMODULE: Prefix_InjectedSubmodule InjectedSubmodule
  ; NOTE(fschuiki): The above should actually read `Prefix_SeqMemsGroup`, but it
  ; is not yet totally clear how to properly order the FIRRTL passes such that
  ; the module generated by `ExtractInstances` gets properly prefixed.
  module DUTModule :
    input clock : Clock
    input reset : Reset
    output io : { foo : { flip addr : UInt<3>, flip dataIn : UInt<8>, flip wen : UInt<1>, dataOut : UInt<8>}, bar : { flip addr : UInt<3>, flip dataIn : UInt<8>, flip wen : UInt<1>, dataOut : UInt<8>}}

    inst inst0 of SomeModule
    connect inst0.clock, clock
    connect inst0.reset, reset
    connect io.foo.dataOut, inst0.io.dataOut
    connect inst0.io.wen, io.foo.wen
    connect inst0.io.dataIn, io.foo.dataIn
    connect inst0.io.addr, io.foo.addr
    inst inst1 of SomeModule_1
    connect inst1.clock, clock
    connect inst1.reset, reset
    connect io.bar.dataOut, inst1.io.dataOut
    connect inst1.io.wen, io.bar.wen
    connect inst1.io.dataIn, io.bar.dataIn
    connect inst1.io.addr, io.bar.addr

  ; TESTHARNESS: module TestHarness
  ; TESTHARNESS: Prefix_DUTModule dut
  ; TESTHARNESS-NOT: mem_ext mem_ext
  ; TESTHARNESS-NOT: Prefix_mem_ext mem_ext
  public module TestHarness :
    input clock : Clock
    input reset : UInt<1>
    output io : { foo : { flip addr : UInt<3>, flip dataIn : UInt<8>, flip wen : UInt<1>, dataOut : UInt<8>}, bar : { flip addr : UInt<3>, flip dataIn : UInt<8>, flip wen : UInt<1>, dataOut : UInt<8>}}

    inst dut of DUTModule
    connect dut.clock, clock
    connect dut.reset, reset
    connect io.bar.dataOut, dut.io.bar.dataOut
    connect dut.io.bar.wen, io.bar.wen
    connect dut.io.bar.dataIn, io.bar.dataIn
    connect dut.io.bar.addr, io.bar.addr
    connect io.foo.dataOut, dut.io.foo.dataOut
    connect dut.io.foo.wen, io.foo.wen
    connect dut.io.foo.dataIn, io.foo.dataIn
    connect dut.io.foo.addr, io.foo.addr

  ; INJECTEDSUBMODULE: module Prefix_InjectedSubmodule
  ; INJECTEDSUBMODULE: Prefix_SomeModule inst0
  ; INJECTEDSUBMODULE: Prefix_SomeModule inst1

  ; SOMEMODULE: module Prefix_SomeModule
  ; SOMEMODULE: Prefix_mem mem

  ; SEQMEMSGROUP: module Prefix_SeqMemsGroup
  ; SEQMEMSGROUP:   mem_wiring_1_R0_addr
  ; SEQMEMSGROUP:   mem_wiring_0_R0_addr
  ; SEQMEMSGROUP: Prefix_mem_ext mem_ext
  ; SEQMEMSGROUP: Prefix_mem_ext mem_ext

  ; MEM: module Prefix_mem
  ; MEM-NOT: mem_ext mem_ext
  ; MEM-NOT: Prefix_mem_ext mem_ext

  ; MEMS-CONF: name Prefix_mem_ext depth 8 width 8 ports write,read
  ; SEQMEMS-TXT: mem_wiring_1 -> Prefix_DUTModule.InjectedSubmodule.inst0.mem
  ; SEQMEMS-TXT: mem_wiring_0 -> Prefix_DUTModule.InjectedSubmodule.inst1.mem

  ; OMIR:      "id": "OMID:0"
  ; OMIR:      "name": "finalPath"
  ; OMIR-NEXT: "value": "OMMemberInstanceTarget:~Prefix_DUTModule|Prefix_DUTModule/SeqMemsGroup:Prefix_SeqMemsGroup/mem_ext{{[^:]*}}:Prefix_mem_ext"
  ; OMIR:      "id": "OMID:1"
  ; OMIR:      "name": "finalPath"
  ; OMIR-NEXT: "value": "OMMemberInstanceTarget:~Prefix_DUTModule|Prefix_DUTModule/SeqMemsGroup:Prefix_SeqMemsGroup/mem_ext{{[^:]*}}:Prefix_mem_ext"
